//+------------------------------------------------------------------+
//|                                             HelloWorldServer.mq4 |
//|                                          Copyright 2016, Li Ding |
//|                                            dingmaotu@hotmail.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, Li Ding"
#property link      "dingmaotu@hotmail.com"
#property version   "1.00"
#property strict

#include <Zmq/Zmq.mqh>

// 全局变量
Context context;
Socket socket(context, ZMQ_REP);
Socket pub_socket(context, ZMQ_PUB);  // 添加发布socket
string subscribed_symbols[];  // 订阅的货币对列表

//+------------------------------------------------------------------+
//| Expert initialization function                                     |
//+------------------------------------------------------------------+
int OnInit()
{
    // 绑定ZMQ socket
    if(!socket.bind("tcp://*:5555"))
    {
        Print("ZMQ绑定失败");
        return INIT_FAILED;
    }
    
    // 绑定发布socket
    if(!pub_socket.bind("tcp://*:5556"))
    {
        Print("ZMQ发布绑定失败");
        return INIT_FAILED;
    }
    
    Print("ZMQ服务器启动成功");
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                   |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    // 关闭ZMQ连接
    socket.unbind("tcp://*:5555");
    socket.disconnect("");
    pub_socket.unbind("tcp://*:5556");
    pub_socket.disconnect("");
    context.destroy(0);
}

//+------------------------------------------------------------------+
//| Expert tick function                                              |
//+------------------------------------------------------------------+
void OnTick()
{
    // 处理客户端请求
    ZmqMsg request;
    if(socket.recv(request, ZMQ_DONTWAIT))  // 非阻塞接收
    {
        string message = request.getData();
        Print("收到消息: ", message);
        
        // 解析命令
        string response = ProcessCommand(message);
        
        // 发送响应
        ZmqMsg reply(response);
        socket.send(reply);
        Print("已发送响应: ", response);
    }
    
    // 推送价格更新
    for(int i = 0; i < ArraySize(subscribed_symbols); i++)
    {
        string symbol = subscribed_symbols[i];
        double bid = MarketInfo(symbol, MODE_BID);
        double ask = MarketInfo(symbol, MODE_ASK);
        
        // 格式：PRICE_UPDATE|SYMBOL|BID|ASK|TIME
        string price_update = StringFormat("PRICE_UPDATE|%s|%.5f|%.5f|%d",
            symbol,
            bid,
            ask,
            TimeCurrent()
        );
        
        ZmqMsg msg(price_update);
        pub_socket.send(msg);
    }
}

//+------------------------------------------------------------------+
//| 处理命令                                                           |
//+------------------------------------------------------------------+
string ProcessCommand(string command)
{
    string parts[];
    StringSplit(command, '|', parts);
    
    if(ArraySize(parts) < 1)
        return "ERROR|无效的命令格式";
        
    string cmd = parts[0];
    
    // 获取账户信息
    if(cmd == "ACCOUNT_INFO")
    {
        return StringFormat("ACCOUNT_INFO|%d|%s|%.2f|%.2f|%.2f",
            AccountNumber(),
            AccountCompany(),
            AccountBalance(),
            AccountEquity(),
            AccountProfit()
        );
    }
    
    // 获取市场数据
    if(cmd == "MARKET_INFO" && ArraySize(parts) >= 2)
    {
        string symbol = parts[1];
        return StringFormat("MARKET_INFO|%s|%.5f|%.5f|%.5f|%.5f",
            symbol,
            MarketInfo(symbol, MODE_BID),
            MarketInfo(symbol, MODE_ASK),
            MarketInfo(symbol, MODE_STOPLEVEL),
            MarketInfo(symbol, MODE_LOTSIZE)
        );
    }
    
    // 获取持仓信息
    if(cmd == "GET_POSITIONS")
    {
        string result = "POSITIONS|";
        int total = OrdersTotal();
        
        for(int i = 0; i < total; i++)
        {
            if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
            {
                // 只返回市价单（OP_BUY和OP_SELL）
                if(OrderType() <= OP_SELL)
                {
                    // 格式：订单号,货币对,类型,手数,开仓价,止损,止盈,盈亏,魔法数字,手续费,隔夜利息
                    result += StringFormat("%d,%s,%d,%.2f,%.5f,%.5f,%.5f,%.2f,%d,%.2f,%.2f;",
                        OrderTicket(),      // 订单号
                        OrderSymbol(),      // 货币对
                        OrderType(),        // 类型（0=买入，1=卖出）
                        OrderLots(),        // 交易量
                        OrderOpenPrice(),   // 开仓价
                        OrderStopLoss(),    // 止损价
                        OrderTakeProfit(),  // 止盈价
                        OrderProfit(),      // 浮动盈亏
                        OrderMagicNumber(), // 魔法数字
                        OrderCommission(),  // 手续费
                        OrderSwap()         // 隔夜利息
                    );
                }
            }
        }
        
        return result;
    }
    
    // 开仓命令
    // 格式: OPEN_ORDER|SYMBOL|TYPE|LOTS|SL|TP|MAGIC
    // 例如: OPEN_ORDER|EURUSD|0|0.1|1.05|1.07|9999
    if(cmd == "OPEN_ORDER" && ArraySize(parts) >= 6)
    {
        string symbol = parts[1];
        int type = (int)StringToInteger(parts[2]);  // 0=BUY, 1=SELL
        double lots = StringToDouble(parts[3]);
        double sl = StringToDouble(parts[4]);
        double tp = StringToDouble(parts[5]);
        int magic = 0;  // 默认魔法数字为0
        
        // 如果提供了魔法数字，则使用它
        if(ArraySize(parts) >= 7)
        {
            magic = (int)StringToInteger(parts[6]);
        }
        
        // 获取当前价格
        double price = (type == OP_BUY) ? Ask : Bid;
        
        // 开仓
        int ticket = OrderSend(
            symbol,     // 货币对
            type,       // 操作类型
            lots,       // 交易量
            price,      // 价格
            3,          // 滑点
            sl,         // 止损
            tp,         // 止盈
            "",         // 注释
            magic,      // magic number
            0,          // 过期时间
            type == OP_BUY ? clrBlue : clrRed  // 颜色
        );
        
        if(ticket > 0)
        {
            return StringFormat("SUCCESS|开仓成功|%d", ticket);
        }
        else
        {
            int error = GetLastError();
            return StringFormat("ERROR|开仓失败|%d|%s", error, "开仓失败，请检查参数");
        }
    }
    
    // 平仓命令
    // 格式: CLOSE_ORDER|TICKET|LOTS
    // 例如: CLOSE_ORDER|12345|0.1
    if(cmd == "CLOSE_ORDER" && ArraySize(parts) >= 2)
    {
        int ticket = (int)StringToInteger(parts[1]);
        double lots = 0;  // 默认平掉全部仓位
        
        // 如果提供了手数，则进行部分平仓
        if(ArraySize(parts) >= 3)
        {
            lots = StringToDouble(parts[2]);
        }
        
        // 选中订单
        if(!OrderSelect(ticket, SELECT_BY_TICKET))
        {
            return StringFormat("ERROR|平仓失败|%d|%s", GetLastError(), "订单不存在");
        }
        
        // 获取订单信息
        string symbol = OrderSymbol();
        int type = OrderType();
        double orderLots = OrderLots();
        
        // 如果指定了手数，确保不超过订单总手数
        if(lots > 0 && lots < orderLots)
        {
            // 部分平仓
            bool result = OrderClose(ticket, lots, type == OP_BUY ? Bid : Ask, 3);
            if(result)
            {
                return StringFormat("SUCCESS|部分平仓成功|%.2f", lots);
            }
            else
            {
                return StringFormat("ERROR|部分平仓失败|%d|%s", GetLastError(), "部分平仓失败");
            }
        }
        else
        {
            // 全部平仓
            bool result = OrderClose(ticket, orderLots, type == OP_BUY ? Bid : Ask, 3);
            if(result)
            {
                return "SUCCESS|全部平仓成功";
            }
            else
            {
                return StringFormat("ERROR|平仓失败|%d|%s", GetLastError(), "平仓失败");
            }
        }
    }
    
    // 修改订单命令
    // 格式: MODIFY_ORDER|TICKET|SL|TP
    // 例如: MODIFY_ORDER|12345|1.05|1.07
    if(cmd == "MODIFY_ORDER" && ArraySize(parts) >= 4)
    {
        int ticket = (int)StringToInteger(parts[1]);
        double sl = StringToDouble(parts[2]);
        double tp = StringToDouble(parts[3]);
        
        // 选中订单
        if(!OrderSelect(ticket, SELECT_BY_TICKET))
        {
            return StringFormat("ERROR|找不到订单|%d", ticket);
        }
        
        // 修改订单
        bool success = OrderModify(
            ticket,         // 订单号
            OrderOpenPrice(), // 保持原开仓价不变
            sl,             // 新止损价
            tp,             // 新止盈价
            0,              // 过期时间
            clrYellow       // 颜色
        );
        
        if(success)
        {
            return StringFormat("SUCCESS|修改成功|%d", ticket);
        }
        else
        {
            int error = GetLastError();
            return StringFormat("ERROR|修改失败|%d|%s", error, "修改订单失败，请检查参数");
        }
    }
    
    // 订阅价格更新
    if(cmd == "SUBSCRIBE_PRICE" && ArraySize(parts) >= 2)
    {
        string symbol = parts[1];
        bool exists = false;
        
        // 检查是否已经订阅
        for(int i = 0; i < ArraySize(subscribed_symbols); i++)
        {
            if(subscribed_symbols[i] == symbol)
            {
                exists = true;
                break;
            }
        }
        
        // 如果未订阅，则添加
        if(!exists)
        {
            int size = ArraySize(subscribed_symbols);
            ArrayResize(subscribed_symbols, size + 1);
            subscribed_symbols[size] = symbol;
        }
        
        return "SUCCESS|订阅成功";
    }
    
    // 取消订阅
    if(cmd == "UNSUBSCRIBE_PRICE" && ArraySize(parts) >= 2)
    {
        string symbol = parts[1];
        int new_size = 0;
        
        // 创建新数组，排除要取消的货币对
        for(int i = 0; i < ArraySize(subscribed_symbols); i++)
        {
            if(subscribed_symbols[i] != symbol)
            {
                subscribed_symbols[new_size] = subscribed_symbols[i];
                new_size++;
            }
        }
        
        // 调整数组大小
        ArrayResize(subscribed_symbols, new_size);
        
        return "SUCCESS|取消订阅成功";
    }
    
    // 获取K线数据
    if(cmd == "GET_BARS" && ArraySize(parts) >= 4)
    {
        string symbol = parts[1];
        int timeframe = (int)StringToInteger(parts[2]);
        int count = (int)StringToInteger(parts[3]);
        
        // 检查参数
        if(!MarketInfo(symbol, MODE_BID))
        {
            return StringFormat("ERROR|无效的货币对: %s", symbol);
        }
        
        string result = "BARS|";
        
        // 从最新的K线开始获取
        for(int i = count-1; i >= 0; i--)
        {
            // 检查是否有数据
            if(iTime(symbol, timeframe, i) == 0)
            {
                continue;
            }
            
            // 获取K线数据
            datetime time = iTime(symbol, timeframe, i);
            double open = iOpen(symbol, timeframe, i);
            double high = iHigh(symbol, timeframe, i);
            double low = iLow(symbol, timeframe, i);
            double close = iClose(symbol, timeframe, i);
            double volume = iVolume(symbol, timeframe, i);
            int spread = (int)MarketInfo(symbol, MODE_SPREAD);
            
            // 添加调试信息
            Print(StringFormat("K线 %d: 时间=%s, 开=%f, 高=%f, 低=%f, 收=%f", 
                i, TimeToStr(time), open, high, low, close));
            
            // 格式：时间|开盘|最高|最低|收盘|成交量|点差;
            result += StringFormat("%d|%.5f|%.5f|%.5f|%.5f|%.2f|%d;",
                time,
                open,
                high,
                low,
                close,
                volume,
                spread
            );
        }
        
        Print("返回数据: " + result);  // 打印返回的数据
        return result;
    }
    
    return "ERROR|未知命令: " + cmd;
}
